#from trans_tree import *

# from my_dbg import *
#Dbg_switch.on(__name__)
class Name_switch:
    def __init__(self):pass
    @staticmethod
    def Camel(name):
        part_list = name.split("_")
        part_list = list(filter(None, part_list))
        r = [token.capitalize() for token in part_list]
        return "".join(r)


____line_print = False
#____line_print = True

def ref_to_class_name(class_ref):
    if class_ref == None:
        return None
    return class_ref[:-1*len("_obj*")]
def class_to_obj_ref(class_name):
    return class_name + "_obj*"

def obj_to_class_name(class_obj):
    
    if class_obj == None:
        return None
    r =  class_obj[:-1*len("_obj")]
    return r

def get_obj_type_single(obj_str, type_space):
    return type_space.get_local_type(obj_str)

def get_sub_member_type(father_class, sub_member_name, type_space):
    return type_space.get_sub_member_type(father_class, sub_member_name)

def get_obj_class_name(obj_str, type_space):
    def ref_sub_member(cur_class_type, sub_member, type_space):
        cur_class_name = ref_to_class_name(cur_class_type)
        next_class_type = get_sub_member_type(cur_class_name, sub_member, type_space)
        return next_class_type
    def obj_sub_member(cur_class_type, sub_member, type_space):
        cur_class_name = obj_to_class_name(cur_class_type)
        next_class_type = get_sub_member_type(cur_class_name, sub_member, type_space)
        return next_class_type
    def obj_sub_member_list(cur_class_type, sub_member_list, type_space):
        for sub_member in sub_member_list:
            cur_class_type = obj_sub_member(cur_class_type, sub_member, type_space)
        return cur_class_type

    switch_ref_flag = False
    if obj_str.startswith("&"):
        obj_str = obj_str[1:]
        switch_ref_flag = True
        
    obj_list = obj_str.split("->")

    cur_class_type = None
    if "." not in obj_list[0]:
        cur_class_type = get_obj_type_single(obj_list[0], type_space)
    else:
        cur_class_name = get_obj_type_single(obj_list[0].split(".")[0].strip(), type_space)
        cur_class_type = obj_sub_member_list(cur_class_type, obj_list[0].split(".")[1:], type_space)
    #debug_buf = []
    for sub_member in obj_list[1:]:
        if "." not in sub_member:
            cur_class_type = ref_sub_member(cur_class_type, sub_member, type_space)
        else:
            sub_member, *sub_member_ext_list = sub_member.split(".")
            cur_class_type = ref_sub_member(cur_class_type, sub_member, type_space)
            cur_class_type = obj_sub_member_list(cur_class_type, list(sub_member_ext_list), type_space)
        #debug_buf.append("sub_member [{sub_member}] next_class_type[{cur_class_type}]".format(**locals()))
    if switch_ref_flag == True:
        return obj_to_class_name(cur_class_type)
    else:
        return ref_to_class_name(cur_class_type)

### type = ret ( param_list ) 
### return     ret (*name) ( param_list )
def type_and_name(Type, name):
    r = "{Type} {name}".format(**locals())
    if Type == None:
        return r
    if "[" in Type:
        ret, rest = Type.split("[", 1)
        r = "{ret} {name}[{rest}".format(**locals())

    if "(" in Type:
        ret, rest = Type.split("(", 1)
        r = "{ret} (*{name})({rest}".format(**locals())
    if name == "__":
        #初始化的时候  
        # *x = 1;
        # __:+x = 1
        r = Type
        #return Type
    if name == Type and name == "__VARIABLE_PARAM__":
        # 可变参数.
        return "..."
    return r

def add_check_after_line_stack(type_space):
    ret_val = type_space.cur_func_info.auto_choice_ret_val()
    type_space.line_stack_after[-1].append(''';                                        DS_EXCEPTON_CHECK("", {ret_val});'''.format(**locals()))

def popall_check_after_line_stack(type_space):
    r = ""
    if len( type_space.line_stack_after[-1] ) > 0:
        r = type_space.line_stack_after[-1][-1]
    type_space.line_stack_after.pop()
    new_stack = []
    type_space.line_stack_after.append(new_stack)
    return r
def ignore_check_after_line_stack(type_space):
    type_space.line_stack_after.pop()
    new_stack = []
    type_space.line_stack_after.append(new_stack)
    type_space.line_stack_after[-1].append(''';                                        Ds_exception__error_ignore(DS_ERROR);'''.format(**locals()))

def jump_check_after_line_stack(type_space):
    type_space.line_stack_after.pop()
    new_stack = []
    type_space.line_stack_after.append(new_stack)
    type_space.line_stack_after[-1].append(''';                                        //tolerate error.'''.format(**locals()))


#############comment
def class_comment(comment):
    r = """
/************************************************
{comment_line_list}
************************************************/
"""
    return comment_util(comment, r, ignore_space=0)
def func_comment(comment):
    r = """
/**
{comment_line_list}
**/
"""
    return comment_util(comment, r, ignore_space=8)
def comment_util(comment, r, ignore_space=8):
    comment_line_list = "\n".join( ["*     "+line[ignore_space:] for line in comment.split(r"\n") if len(line)>=ignore_space] )
    return r.format(**locals()).strip()

###############################################################################
def _AnnAssign_proc(target, annotation, value, type_space):
    type_space.set_local(target, annotation)
    type_name = type_and_name(annotation, target)
    r = "{type_name} = {value}"
    if value == _NoneType_proc():
        r = "{type_name}"
    return r.format(**locals())

def _NoneType_proc(): return "NoneType"
def _Pass_proc(): return "_Pass"


def _For_proc(i, Iter, obj_name, body, type_space):
    r = None
    if "range" in obj_name:
        
        start, end = obj_name.split("(", 1)[1].split(")", 1)[0].split(",")
        start, end = start.strip(), end.strip()
        Range = obj_name
        r = "FOR_RANGE({Iter}, {start}, {end})".format(**locals())
    else:
        class_name = get_obj_class_name(obj_name, type_space)
        r = "FOR_EACH({Iter}, {class_name}, {obj_name})"
        if i != None:
            r = "FOR_EACH_I({i}, {Iter}, {class_name}, {obj_name})"
    
    r = (r + "\n{{\n{body};\n}}").format(**locals())
    return r

def _arg_proc(arg, annotation, class_name, type_space, ext_opt):
    r = None
    Type, name = annotation, arg
    if ext_opt == "func_param":
        type_space.set_local(name, Type)
    return type_and_name(Type, name)

def _Str_proc(s, type_space):
    # c代码嵌入
    # 用同样的方法嵌入空行
    source_c_flag = "// "
    flag_len = len(source_c_flag)
    if len(s) >= flag_len and s[:flag_len] == source_c_flag:
        source_c = s[flag_len:]
        source_c = "\n".join([line.strip() for line in source_c.splitlines()])
        return source_c
    comment_flag = "## "
    flag_len = len(comment_flag)
    if len(s) >= flag_len and s[:flag_len] == comment_flag:
        source_c = s[flag_len:].strip()
        source_c = "\n".join(["// "+line.strip() for line in source_c.splitlines()])
        return source_c
    
        # source_c = [line[8:] for line in source_c.splitlines() ]
        # r = "\n".join(source_c)
        # return r
    # # 注释
    # comment_flag = "~!@"
    # flag_len = len(comment_flag)
    # if len(s) > flag_len and s[:flag_len] == comment_flag:
    #     return ""
    #proc c string:
    s = "\\n".join(s.split("\n"))
    s = "\\t".join(s.split("\t"))
    return '"{s}"'.format(**locals())




#############################################################
# 函数指针的参数 要在本地变量中声明。
def _arguments_proc(func_name, func_type, type_space):
    returns, args = func_type.rsplit(")", 1)[0].split("(", 1)
    deco_list = ["staticmethod"]
    class_name = "local_func_param"     #not use. mark
    func_info = Func_info(class_name, func_name, returns, args, deco_list)
    type_space.set_local(func_name, func_info)
    return func_info.type_line()
    # if returns != "void":
    #     args = ", ".join([returns+"*", args])
    # return "void* (*{func_name})({args})".format(**locals())

class Func_info:
    def __init__(self, class_name, func_name, returns, args, deco_list):
        self.name = func_name
        self.class_name = class_name
        self.returns = returns
        self.deco_list = deco_list
        self.args = args
    #debug 
    def __str__(self):
        returns, class_name, name, args, deco_list = str(self.returns), self.class_name, self.name, self.args, str(self.deco_list)
        return "{returns} {class_name}__{name}({args});\n{deco_list}".format(**locals())
    def is_static(self):
        return "staticmethod" in self.deco_list
    def No_prepare_check(self):
        return "No_prepare_check" in self.deco_list
    def add_source(self, type_space, obj):
        obj_name = self.name.split("__", 1)[0]
        if not self.is_static():
            obj_name = obj
            # obj_name = self.args.split(",", 1)[0].split(" ", 1)[1]
        class_name = self.class_name
        for deco in self.deco_list:
            if deco.startswith("__source"):
                free_method = deco.split("(", 1)[1].rsplit(")", 1)[0]
                #call_code = direct_call("{class_name}__{free_method}".format(**locals()), [obj_name], type_space, self)
                # ret_val = type_space.cur_func_info.auto_choice_ret_val()
                
                free_func = Name_switch.Camel(class_name+"_"+free_method)
                ##!! free_func
                #call_code = """{class_name}__{free_method}({obj_name}, DS_ERROR)""".format(**locals())
                call_code = """{free_func}({obj_name}, DS_ERROR)""".format(**locals())
                add_check_after_line_stack(type_space)
                #type_space.src_add("{class_name}__{free_method}({obj_name})".format(**locals()))
                type_space.src.add_src(call_code)
        #direct_call(func, args, type_space, func_info)


    # 函数定义的时候
    # 设置装饰器中 声明的c函数。
    # @c_func({func_name})
    def set_local(self, type_space):
        c_func = []
        for deco in self.deco_list:
            if deco.startswith("c_func"):
                func_name = deco.split("(", 1)[1].split(")", 1)[0].strip()
                c_func.append(func_name)
        # if self.returns != NULL:

        type_space.set_local("decorate_c_func", c_func)
    def def_line(self):
        ret = ""
        returns, args, class_name, name = self.returns, self.args, self.class_name, self.name
        arg_list = list(filter(None,   args.strip().split(",")  ))
        if "No_throw" not in self.deco_list:
            arg_list.append("void** DS_ERROR")
        if len(arg_list) > 2 and arg_list[-2].strip() == "...":
            # c语言可变参数宏
            # va_start要求： 最后一个参数必须是参数个数。
            # 我们把DS_ERROR放在倒数第三个参数
            arg_list = arg_list[:-3] + [arg_list[-1], arg_list[-3], arg_list[-2]]
        #args = args.strip().split(",") + [" void** DS_ERROR"]
        args = ",".join( arg_list )
        if returns == None:
            OO_info(str(self))
        if returns.strip() != "void":
            ret = "{returns} *ret".format(**locals())
        
        
        #arg_list = args.split(",", 1)
        # if self.is_static():
        #     args = ", ".join(list( filter(None, [args.strip()])))
        # else:
        #     args += 
            # if ret != "":
            #     arg_list = args.split(",", 1)
            #     arg_list = arg_list[:1] + [ret] + arg_list[1:] 
            #     args = ", ".join(arg_list)

        # if "self" in args and ret != "":
        #     arg_list = args.split(",", 1)
        #     arg_list = arg_list[:1] + [ret] + arg_list[1:] 
        #     args = ", ".join(arg_list)
        # else:
        #     args = ", ".join(list( filter(None, [ret.strip(), args.strip()])))

        #args = ret if args.strip() == "" else args if ret.strip() == "" else "{ret}, {args}".format(**locals())
        
        ##!! 函数定义时刻的名字
        func_name = Name_switch.Camel(class_name+"_"+name)
        #func_line = "{returns} {class_name}__{name}({args})".format(**locals())
        func_line = "{returns} {func_name}({args})".format(**locals())
        
        return func_line
    def type_line(self):
        returns, name, args = self.returns, self.name, self.args
        args = args.strip().split(",") + ["void**"]
        args = ",".join(args)
        return "{returns} (*{name})({args})".format(**locals())

    def ret_type(self):
        if self.returns != "void":
            return self.returns
        return None
    def auto_choice_ret_val(self):
        ret_val = "-1"
        if self.ret_type() == None:
            ret_val = "DS_RETURN_VOID"
        else:
            if "*" in self.ret_type():
                ret_val = "NULL"
        return ret_val
#在这里加入如果是函数指针的设定？

def _FunctionDef_proc(class_name, func_name, returns, args, deco_list, type_space):

    func_info = Func_info(class_name, func_name, returns, args, deco_list)
    type_space.add_func(class_name, func_info)
    func_info.set_local(type_space)
    type_space.cur_func_info = func_info
    #type_space.set_local("deco_list", deco_list)
    r = func_info.def_line()
    if ____line_print == True:
        OO_info(r)
    return r
# def free_src_list(type_space):
#     return type_space.src.func_src_list()
    # r = type_space.src_find_all()
    # # 彈栈顺序和 入栈顺序相反,
    # # 在一个依次打开两个资源的类中, 资源释放的顺序就必须逆序.
    # r = r[::-1]
    # return r
def _Continue_proc(type_space):
    return ";\n".join( type_space.src.break_continue_src_list() + ["continue"] )
def _Break_proc(type_space):
    return ";\n".join( type_space.src.break_continue_src_list() + ["break"] )
def _Return_proc(value, type_space):
    #r = free_src_list(type_space)
    r = []
    if value == "NoneType":
        value = ""
    # 函数调用
    if "__" in value:
        ret_type = type_space.cur_func_info.returns
        culc_val = "{ret_type} RETURN_VAL = {value}".format(**locals()) 
        culc_val += popall_check_after_line_stack(type_space)
        r.append(culc_val)
        value = "RETURN_VAL"
    r += type_space.src.return_raise_src_list()
    r.append("return {value}".format(**locals()))
    
    return ";\n".join( r ) 

def _Raise_proc(value, type_space):
    ret_val = type_space.cur_func_info.auto_choice_ret_val()
    #r = free_src_list(type_space)
    r = type_space.src.return_raise_src_list()
    #quit = 'Ds_exception__quit(&DS_ERROR, __LINE__, __func__, {value}); return DS_ERROR;'.format(**locals())
    quit = "DS_EXCEPTION_RETURN(DS_ERROR, {value}, {ret_val})".format(**locals())
    # if value == "NULL":
    #     quit = "return -1;"
    r.append( quit )
    return ";\n".join( r )
def _func_prepare(type_space):
    ret_val = type_space.cur_func_info.auto_choice_ret_val()
    prepare_check =  "DS_PREPARE_CHECK({ret_val})".format(**locals())
    # cancel prepare check
    if type_space.cur_func_info.No_prepare_check():
        prepare_check = ""
    return prepare_check


#处理面向对象
def _Call_proc(func, args, type_space):
    #OOvar(__name__, func, "func")
    #direct call
    
    r = None
    
    if "->" not in func:
        #OOvar(__name__, "direct", 'B')
        func_info = type_space.get_local_type(func)
        #r =  direct_call(func, args, type_space)
    else:
        # # if "(" in func:
        # #     r = sequence_call(func, args, type_space)
        # else:
        #OOvar(__name__, func, args)
        try:
            obj_name, func_name = func.rsplit("->", 1)
        except Exception as e:
            OO_info(func)
            raise e
        args = [obj_name] + args

        # type_name = type_space.get_local_type(obj_name)
        # class_name = ref_to_class_name(type_name)
        class_name = get_obj_class_name(obj_name, type_space)

        if class_name == None:
            class_name = obj_name
            args = args[1:]
        func = "{class_name}__{func_name}".format(**locals())
        func_info = type_space.get_func(class_name, func_name)
    r =  direct_call(func, args, type_space, func_info)

    return r
# def sequence_call(func, args, type_space):
#     # 函数的返回值作为对象， 继续调用方法。 这里默认返回值必须是 this 指针。
#     class_name = func.split("__", 1)[0]
#     obj, func_name = func.rsplit("->", 1)
#     args = ", ".join([obj] + args)
#     r = "{class_name}__{func_name}({args})".format(**locals())
#     return r
#处理特殊函数
def direct_call(func, args, type_space, func_info):
    #特殊处理函数
    #func = Name_switch.Camel(func)

    if hasattr(Special_call, "_Special_call"+func):
        #静态函数的特殊字符串
        call = eval("Special_call._Special_call"+func)
        return call(func, args, type_space)
    if func in  Special_call.c_func:
        return Special_call.c_func_proc(func, args, type_space)
    
    
    #一般函数
    else:
        
        arg_str = ", ".join(args)
        r = "{func}({arg_str})".format(**locals())
        
        c_declare_funcs = type_space.get_local_type("decorate_c_func")
        # 声明的c函数   在调用的时候不会改写返回值。
        # 否则改写返回值，异常
        if c_declare_funcs == None or func not in c_declare_funcs:
            
            if func_info == None:
                arg_str = ", ".join(args)
                OO_info("{func} ({arg_str})".format(**locals()))
                raise Exception("Error :: func {func} not record. func_info == None".format(**locals()))
            
            
            # c 语言可变参数宏:
            # DS_ERROR必须在中间。在可变参数的数字之前。
            # 我们约定如果DS_ERROR已经在args之中（手动指定DS_ERROR位置）
            # 那么我们就不再在末尾增加DS_ERROR
            if "DS_ERROR" not in args:
                if "No_throw" not in func_info.deco_list:
                    args.append("DS_ERROR")
            arg_str = ", ".join(args)
            #ret_val = type_space.cur_func_info.auto_choice_ret_val()
            # ret_val = "-1"
            # if func_info.ret_type() == None:
            #     ret_val = "void"

            ##!! 修改了函数调用的名字。
            func = Name_switch.Camel(func)
            r = """{func}({arg_str})""".format(**locals())
            add_check_after_line_stack(type_space)

#             r = """
# if ( DS_ERROR = {func}({arg_list}) )
# {{
# {Raise};
# }}
# """
#             add_tab = lambda s: "\n".join( [" "*4+ line for line in s.splitlines()])
#             Raise = add_tab( _Raise_proc('""', type_space) )
#             if "\n" not in Raise:
#                 #r = """DS_ERROR = {func}({arg_list});                                         if(DS_ERROR){{ {Raise} }}"""
#                 r = """DS_ERROR = {func}({arg_list});                                         DS_EXCEPTON_CHECK("")"""


            obj = args[0] if len(args)>0 else None
            func_info.add_source(type_space, obj)
            
#             ret_type = func_info.ret_type()
#             if ret_type != None:
#                 index = type_space.get_local_type("AUTO_RETURN_INDEX")
#                 if index == None:
#                     index = 0
#                 type_space.set_local("AUTO_RETURN_INDEX", index+1)
#                 #tem_num = str(tem_num)
#                 ret_var = "{func}__{index}".format(**locals())

#                 if func_info.is_static():
#                     args = ["&"+ret_var] + args
#                 else:
#                     args = args[:1] + ["&"+ret_var] + args[1:]
#                 type_space.func_stack.append("{ret_type} {ret_var}".format(**locals()))
#                 arg_list = ", ".join(args)
#                 type_space.line_stack[-1].append(r.format(**locals()))
#                 r = ret_var
            
#             r = r.format(**locals())
        if ____line_print == True:
            OO_info(r)
        return r

class Special_call:
    c_func = ["range", "printf", "fprintf", "c_func", "Memory_free", "sizeof", "enumerate", "FUNC_cp", "FUNC_cc","MYSQL_DBG",
        "FUNC_ci", "FUNC_cf", "FUNC_AT", "Array_SHOW", "MEMORY_CALC_PROC_TUPLE_UNPACK", "MEMORY_REALLOC_PROC_TUPLE_UNPACK", "__source", "__pack",
        "exception_quit", "__comment", "__under", "FUNC_push", "FUNC_pop",
        #"___ut_eq", "___ut_gt", 
        "UtEq", "UtGt",
    ]
    def c_func_proc(func, args, type_space):
        arg_str = ", ".join( args )
        return "{func}({arg_str})".format(**locals())

    def __keep_source(func, args, type_space):
        #type_space.src_cancel()
        type_space.src.pop_src()
        return args[0]
    def __error_ignore(func, args, type_space):
        ignore_check_after_line_stack(type_space)
        return args[0]
    # 本行既不消除错误, 也不因为出错而返回.
    def __error_tolerate(func, args, type_space):
        jump_check_after_line_stack(type_space)
        return args[0]
    def __assign(func, args, type_space):
        name, value = args
        return "{name} = {value}".format(**locals())
    def __ptr(func, args, type_space):
        return "{Type}*".format(Type=args[0])
    def __cast(func, args, type_space):
        Type, expr = args
        return "({Type}){expr}".format(**locals())
    def __addr(func, args, type_space):
        return "&{var}".format(var=args[0])
    def __const(func, args, type_space):
        return "const {Type}".format(Type=args[0])
    #函数指针类型
    def __func(func, args, type_space):
        ret =  args[0]
        rest = ", ".join(args[1:])
        return "{ret}({rest})".format(**locals())
    def __unsigned(func, args, type_space):
        return "unsigned {Type}".format(Type=args[0])
    def __long(func, args, type_space):
        return "long {Type}".format(Type=args[0])
    def __struct(func, args, type_space):
        return "struct {Type}".format(Type=args[0])
    def __bracket(func, args, type_space):
        return "({Expr})".format(Expr=args[0])
    def __char(func, args, type_space):
        return "'{char}'".format(char=args[0][1:-1])
    def __array(func, args, type_space):
        #__array({value}, {Slice})
        value, Slice = args
        return "{value}[{Slice}]".format(**locals())



    def __data(func, args, type_space):
        #OBJ_DATA(CLASS_NAME, var_name)
        class_name, var_name = args
        type_name = class_to_obj_ref(class_name)
        type_space.set_local(var_name, type_name)
        #OOvar(__name__, type_space, var_name)
        return "__data({class_name}, {var_name})".format(**locals())
    def __data_heap(func, args, type_space):
        #OBJ_DATA(CLASS_NAME, var_name)
        class_name, var_name = args
        type_name = class_to_obj_ref(class_name)
        type_space.set_local(var_name, type_name)
        #OOvar(__name__, type_space, var_name)
        return "__data_heap({class_name}, {var_name})".format(**locals())
    def __member_func(func, args, type_space):
        class_name, func_name = args
        return "{class_name}__{func_name}".format(**locals())
    def __member(func, args, type_space):
        obj_name, attr_name = args
        return "{obj_name}.{attr_name}".format(**locals())
    def __c_code(func, args, type_space):
        return "\n".join( args[0][1:-1].split("\\n") )


    # def __FIB_HEAP_TRAVERSE_TUPLE_UNPACK(func, args, type_space):
    #     #TUPLE, Fib_heap_obj, FIB_HEAP, Fib_node_obj, NODE
    #     tp, fib_heap, node = args
    #     type_space.set_local(fib_heap, "Fib_heap_obj*")
    #     type_space.set_local(node, "Fib_node_obj*")
    #     return "__FIB_HEAP_TRAVERSE_TUPLE_UNPACK({tp}, {fib_heap}, {node})".format(**locals())



    # {var} = {_enter};
    # if ({_cond})
    # {{
    # {tab_body}
    # {tab_exit}
    # }}
    # """.format(**locals())
    #             if len(error_proc) > 0:
    #                 tab_error_proc = tab_and_quote( error_proc )
    #                 r += """else
    # {{
    # {tab_error_proc};
    # }}
#     def __malloc(func, args, type_space):
#         type_str, mem_size, ret = args
#         type_str = type_str[1:-1]
#         mem_size = str(mem_size)
#         def opt_maker(var):
#             _enter = "({type_str})malloc({mem_size})".format(type_str=type_str, mem_size=mem_size)
#             _cond = "{var} != NULL".format(**locals())
#             _exit = """free({var})
# {var} = NULL""".format(**locals())
#             _error_proc = "{ret} = -1".format(ret=ret)
#             return var, _enter, _cond, _exit, _error_proc
#         return opt_maker
#     def __fmt_alloc(func, args, type_space):
#         fmt, max_size, arg_num, *rest_args = args

#         type_str = type_str[1:-1]
#         mem_size = str(mem_size)
#         def opt_maker(var):
#             _enter = "DS_format_alloc({fmt}, {max_size}, {arg_num}, {rest_args})".format(type_str=type_str, mem_size=mem_size)
#             _cond = "{var} != NULL".format(**locals())
#             _exit = """free({var})
# {var} = NULL""".format(**locals())
#             _error_proc = ""#"{ret} = -1".format(ret=ret)
#             return var, _enter, _cond, _exit, _error_proc
#         return opt_maker
    
    # def __open(func, args, type_space):
    #     _error_proc = ""
    #     _enter, _cond, _exit = args[:3]
    #     if len(args) > 3:
    #         _error_proc = "\n".join(args[3:])
    #     def opt_maker(var):
    #         return var, _enter, _cond, _exit, _error_proc
    #     return opt_maker
    # def __enter(func, args, type_space):
    #     return str(args)
    # {var} = {_enter};
    # if ({_cond})
    # {{
    # {tab_body}
    # {tab_exit}
    # }}
    # """.format(**locals())
    #             if len(error_proc) > 0:
    #                 tab_error_proc = tab_and_quote( error_proc )
    #                 r += """else
    # {{
    # {tab_error_proc};
    # }}